package com.landian.commons.jpa.reposiotry;

import com.landian.commons.base.hql.Searchable;
import com.landian.commons.jpa.criteria.Predicable;
import com.landian.commons.jpa.criteria.PredicableContainer;
import com.landian.commons.jpa.hql.ListHql;
import com.landian.commons.jpa.hql.ListHqlContext;
import com.landian.commons.jpa.hql.PageHql;
import com.landian.commons.jpa.hql.ParameterUnit;
import com.landian.commons.jpa.order.Order;
import com.landian.commons.jpa.order.OrderUnit;
import com.landian.commons.jpa.order.OrderUnitContainer;
import com.landian.commons.jpa.update.UpdateUnit;
import com.landian.commons.jpa.update.UpdateUnitContainer;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Tuple;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
 *
 * @author caojl
 * @create 2017/11/29
 **/
@NoRepositoryBean
@Transactional(readOnly=true,rollbackFor = Exception.class)
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>, JpaSpecificationExecutor<T> {

    /**
     * 是否存在
     * @param predicable
     * @return
     */
    long count(Predicable... predicable);

    /**
     * 查询总数
     * @param searchable 可查询对象
     * @param predicable 扩展查询条件
     * @return
     */
    long count(Searchable searchable, Predicable... predicable);

    /**
     * 是否存在
     * @param predicable
     * @return
     */
    boolean exists(Predicable... predicable);

    /**
     * findTop
     * @param size
     * @return
     */
    List<T> findTop(int size);

    /**
     * findTop
     * @param size
     * @param orders
     * @return
     */
    List<T> findTop(int size, Order... orders);

    /**
     * findTop
     * @param size 条数
     * @param sort 排序容器
     * @param predicable 不定条件
     * @return
     */
    List<T> findTop(int size, com.landian.commons.jpa.order.Sort sort, Predicable... predicable);

    /**
     * findList
     * @param predicable
     * @return
     */
    List<T> findList(Predicable... predicable);

    /**
     * findList
     * @param orders
     * @return
     */
    List<T> findList(Order... orders);

    /**
     *
     * findList
     * @deprecated Use {@link com.landian.commons.jpa.reposiotry.BaseRepository#findList(
     *  com.landian.commons.jpa.criteria.Predicable, com.landian.commons.jpa.order.Sort)} instead.
     * @param predicable
     * @param sort
     * @return
     */
    @Deprecated
    List<T> findList(Predicable predicable, Sort sort);

    /**
     *
     * findList
     * @param predicable
     * @param sort
     * @return
     */
    List<T> findList(Predicable predicable, com.landian.commons.jpa.order.Sort sort);

    /**
     *
     * findList
     * @deprecated Use {@link BaseRepository#findList(com.landian.commons.jpa.criteria.Predicable, com.landian.commons.jpa.order.Order)} instead.
     * @param predicable
     * @param order
     * @return
     */
    @Deprecated
    List<T> findList(Predicable predicable, OrderUnit order);

    /**
     *
     * findList
     * @param predicable
     * @param order
     * @return
     */
    List<T> findList(Predicable predicable, Order order);

    /**
     * findList
     * @param predicableList
     * @return
     */
    List<T> findList(List<Predicable> predicableList);

    /**
     * findList
     * @deprecated Use {@link BaseRepository#findList(com.landian.commons.jpa.order.OrderUnit, com.landian.commons.jpa.criteria.Predicable...)} instead.
     * @param sort
     * @param predicable
     * @return
     */
    @Deprecated
    List<T> findList(Sort sort, Predicable... predicable);

    /**
     * findList
     * @deprecated Use {@link BaseRepository#findList(com.landian.commons.jpa.order.Order, com.landian.commons.jpa.criteria.Predicable...)} instead.
     * @param orderUnit
     * @param predicable
     * @return
     */
    @Deprecated
    List<T> findList(OrderUnit orderUnit, Predicable... predicable);

    /**
     * findList
     * @param order
     * @param predicable
     * @return
     */
    List<T> findList(Order order, Predicable... predicable);

    /**
     * findList
     * @param searchVo
     * @return
     */
    List<T> findList(Searchable searchVo);

    /**
     * findList
     * @deprecated Use {@link BaseRepository#findList(com.landian.commons.base.hql.Searchable, com.landian.commons.jpa.order.Order...)} instead.
     * @param searchable
     * @param orderUnit
     * @return
     */
    @Deprecated
    List<T> findList(Searchable searchable, OrderUnit... orderUnit);

    /**
     * findList
     * @param searchable
     * @param orders
     * @return
     */
    List<T> findList(Searchable searchable, Order... orders);

    /**
     * findPage
     * @param searchable
     * @param pageable
     * @return
     */
    Page<T> findPage(Searchable searchable, Pageable pageable);

    /**
     * findPage
     * @param predicableList
     * @param pageable
     * @return
     */
    Page<T> findPage(List<Predicable> predicableList, Pageable pageable);

    /**
     * findPage
     * @param pageable
     * @param predicable
     * @return
     */
    Page<T> findPage(Pageable pageable, Predicable... predicable);

    /**
     * findPage
     * @param searchable
     * @param pageable
     * @param predicable
     * @return
     */
    Page<T> findPage(Searchable searchable, Pageable pageable, Predicable... predicable);

    /**
     * countByHQL
     * @param hql
     * @return
     */
    Long countByHQL(String hql);

    /**
     * countByHQL
     * @param hql
     * @return
     */
    Long countByHQL(String hql, List<ParameterUnit> parameterUnitList);

    /**
     * findByHQL
     * @param hql
     * @return
     */
    List<T> findByHQL(String hql);

    /**
     * findByHQL
     * @param hql
     * @param countHQL
     * @param pageable
     * @return
     */
    Page<T> findByHQL(String hql, String countHQL, Pageable pageable);

    /**
     * findByHQL
     * @param hql
     * @param parameterUnitList
     * @return
     */
    List<T> findByHQL(String hql, List<ParameterUnit> parameterUnitList);

    /**
     * findByHQL
     * @param hql
     * @param countHQL
     * @param parameterUnitList
     * @param pageable
     * @return
     */
    Page<T> findByHQL(String hql, String countHQL, List<ParameterUnit> parameterUnitList, Pageable pageable);

    /**
     * 根据属性等于查询
     * @param dslPath
     * @param value
     * @return
     */
    List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value);

    /**
     * 根据属性等于查询
     * @deprecated Use {@link BaseRepository#findByPathEqual(com.querydsl.core.types.Path, java.lang.Object, com.landian.commons.jpa.order.Order)} instead.
     * @param dslPath
     * @param value
     * @param orderUnit
     * @return
     */
    @Deprecated
    List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value, OrderUnit orderUnit);

    /**
     * 根据属性等于查询
     * @param dslPath
     * @param value
     * @param order
     * @return
     */
    List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value, Order order);

    /**
     * 根据属性等于查询
     * @deprecated Use {@link BaseRepository#findByPathEqual(com.querydsl.core.types.Path, java.lang.Object, com.landian.commons.jpa.order.Sort)} instead.
     * @param dslPath
     * @param value
     * @param sort
     * @return
     */
    @Deprecated
    List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value, Sort sort);

    /**
     * 根据属性等于查询
     * @param dslPath
     * @param value
     * @param sort
     * @return
     */
    List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value,
                            com.landian.commons.jpa.order.Sort sort);

    /**
     * 根据属性在指定值范围查询
     * @param dslPath
     * @param collection
     * @return
     */
    List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection);

    /**
     * findByPathIn
     * @deprecated Use {@link BaseRepository#findByPathIn(
     * com.querydsl.core.types.Path, java.util.Collection, com.landian.commons.jpa.order.Sort)} instead.
     * 根据属性在指定值范围查询
     * @param dslPath
     * @param collection
     * @param sort
     * @return
     */
    @Deprecated
    List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection, Sort sort);

    /**
     * 根据属性在指定值范围查询
     * @param dslPath
     * @param collection
     * @param order
     * @return
     */
    List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection,
                         com.landian.commons.jpa.order.Order order);

    /**
     * 根据属性在指定值范围查询
     * @param dslPath
     * @param collection
     * @param sort
     * @return
     */
    List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection,
                         com.landian.commons.jpa.order.Sort sort);

    /**
     * findByHQL
     * @param listHql
     * @return
     */
    List<T> findByHQL(ListHql listHql);

    /**
     * findByHQL
     * @param pageHql
     * @param pageable
     * @return
     */
    Page<T> findByHQL(PageHql pageHql, Pageable pageable);

    /**
     * listBySQL
     * @param sql
     * @return
     */
    List<Object[]> listBySQL(String sql);

    /**
     * listByHQL
     * @param hql
     * @return
     */
    List<Object[]> listByHQL(String hql);

    /**
     * listByHQLAsSingleList
     * @param listHqlContext
     * @param clazz
     * @return
     */
    <K> List<K> listByHQLAsSingleList(ListHqlContext listHqlContext, Class<K> clazz);

    /**
     * listByHQLAsSingleResult
     * @param listHqlContext
     * @param clazz
     * @return
     */
    <K> Optional<K> listByHQLAsSingleResult(ListHqlContext listHqlContext, Class<K> clazz);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath);

    /**
     * 查询指定属性的所用值
     * @deprecated Use {@link BaseRepository#listField(com.querydsl.core.types.Path, com.landian.commons.jpa.order.Order...)} instead.
     * @param dslPath
     * @param orderUnit
     * @return
     */
    @Deprecated
    List listField(com.querydsl.core.types.Path<?> dslPath, OrderUnit... orderUnit);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @param orders
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath,
                   com.landian.commons.jpa.order.Order... orders);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @param predicable
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath, Predicable... predicable);

    /**
     * 查询指定属性的所用值
     * @deprecated Use {@link BaseRepository#listField(com.querydsl.core.types.Path, com.landian.commons.jpa.criteria.Predicable, com.landian.commons.jpa.order.Order)} instead.
     * @param dslPath
     * @param predicable
     * @param orderUnit
     * @return
     */
    @Deprecated
    List listField(com.querydsl.core.types.Path<?> dslPath, Predicable predicable, OrderUnit orderUnit);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @param predicable
     * @param order
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath, Predicable predicable,
                   com.landian.commons.jpa.order.Order order);

    /**
     * 查询指定属性的所用值
     * @deprecated Use {@link BaseRepository#listField(com.querydsl.core.types.Path, com.landian.commons.jpa.order.Sort)} instead.
     * @param dslPath
     * @param orderUnitContainer
     * @return
     */
    @Deprecated
    List listField(com.querydsl.core.types.Path<?> dslPath, OrderUnitContainer orderUnitContainer);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @param sort
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath, com.landian.commons.jpa.order.Sort sort);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @param predicableContainer
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath, PredicableContainer predicableContainer);

    /**
     * 查询指定属性的所用值
     * @deprecated Use {@link BaseRepository#listField(com.querydsl.core.types.Path, com.landian.commons.jpa.criteria.PredicableContainer, com.landian.commons.jpa.order.Sort)} instead.
     * @param dslPath
     * @param predicableContainer
     * @param orderUnitContainer
     * @return
     */
    @Deprecated
    List listField(com.querydsl.core.types.Path<?> dslPath, PredicableContainer predicableContainer,
                   OrderUnitContainer orderUnitContainer);

    /**
     * 查询指定属性的所用值
     * @param dslPath
     * @param predicableContainer
     * @param sort
     * @return
     */
    List listField(com.querydsl.core.types.Path<?> dslPath, PredicableContainer predicableContainer,
                   com.landian.commons.jpa.order.Sort sort);

    /**
     * listTuple
     * @param pathArr
     * @return
     */
    List<Tuple> listTuple(com.querydsl.core.types.Path<?>... pathArr);

    /**
     * listTuple
     * @deprecated Use {@link BaseRepository#listTuple(java.util.List, com.landian.commons.jpa.criteria.PredicableContainer, com.landian.commons.jpa.order.Sort)} instead.
     * @param pathList
     * @param predicableContainer
     * @param orderUnitContainer
     * @return
     */
    @Deprecated
    List<Tuple> listTuple(List<com.querydsl.core.types.Path<?>> pathList,
              PredicableContainer predicableContainer, OrderUnitContainer orderUnitContainer);

    /**
     * listTuple
     * @param pathList
     * @param predicableContainer
     * @param sort
     * @return
     */
    List<Tuple> listTuple(List<com.querydsl.core.types.Path<?>> pathList,
              PredicableContainer predicableContainer, com.landian.commons.jpa.order.Sort sort);

    /**
     * hqlAsSingleList
     * 通用查询单值列表hql抽象接口，具体类型调用方自行泛型处理
     * @param hql
     * @return
     */
    List hqlAsSingleList(String hql);

    /**
     * updateBySql
     * @param sql
     * @param args
     */
    @Transactional(rollbackFor = Exception.class)
    void updateBySql(String sql, Object... args);

    /**
     * updateByHql
     * @param hql
     * @param args
     */
    @Transactional(rollbackFor = Exception.class)
    void updateByHql(String hql, Object... args);

    /**
     * update
     * @param id
     * @param idPath 实体的ID对应的Path
     * @param updatePath 更新属性对应的Path
     * @param value 更新值
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    int update(String id, com.querydsl.core.types.Path<?> idPath,
               com.querydsl.core.types.Path<?> updatePath, Object value);

    /**
     * update
     * @param id
     * @param idPath 实体的ID对应的Path
     * @param updateUnits
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    int update(String id, com.querydsl.core.types.Path<?> idPath, UpdateUnit... updateUnits);


    /**
     * update
     * @param id
     * @param idPath 实体的ID对应的Path
     * @param updateUnitContainer
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    int update(String id, com.querydsl.core.types.Path<?> idPath, UpdateUnitContainer updateUnitContainer);

    /**
     * update
     * @param updateUnit 更新单元
     * @param predicableArr 更新条件
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    int update(UpdateUnit updateUnit, Predicable... predicableArr);

    /**
     * delete
     * @param predicable
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    int delete(Predicable... predicable);
}
